package com.app.system.config.shiro;

import com.app.system.config.jwt.JwTUtils;
import com.app.system.config.jwt.JwtToken;
import com.app.system.permission.en.Status;
import com.app.system.permission.en.UserState;
import com.app.system.permission.model.SysPermission;
import com.app.system.permission.model.SysRole;
import com.app.system.permission.model.UserInfo;
import com.app.system.permission.service.UserInfoService;
import com.google.common.collect.Lists;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;


@SuppressWarnings("all")
public class MyShiroRealm extends AuthorizingRealm {
    @Resource
    private UserInfoService userInfoService;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }


    /**
     * 主要是用来进行身份认证的，也就是说验证用户输入的账号和密码是否正确。
     * 登录页面调用LoginController中validate发放时，触发currentUser.login(token)时，自动进入该方法中进行相关验证，在这里里面可以处理更加细致的内容项
     */
    @Override
    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        if (principal.indexOf(".") > 0) {//含有点的，则按照token方式进行登录验证
            String credentials = (String) token.getCredentials();
            String username = JwTUtils.getUsername(principal);
            UserInfo userInfo = userInfoService.findByUsername(username);
            if (userInfo == null) {
                throw new UnknownAccountException(); // 账号不存在
            }
            if (userInfo.getState() == Status.NO.getIndex()) {
                throw new LockedAccountException("账户已锁定，请联系技术人员");
            }
            if (!JwTUtils.verify(principal, userInfo.getUsername(), userInfo.getPassword())) {
                throw new UnknownAccountException("用户名/密码错误");
            }
            System.out.println("=====" + getName());
            return new SimpleAuthenticationInfo(principal, principal, getName());
        } else {
            String username = principal;
            UserInfo userInfo = userInfoService.findByUsername(username);
            if (userInfo == null) {
                throw new UnknownAccountException(); // 账号不存在
            }
            if (userInfo.getState() == UserState.DISABLE.getIndex()) {
                throw new LockedAccountException("账户已锁定，请联系技术人员");
            }

            String password = userInfo.getPassword();
            ByteSource credentialsSalt = ByteSource.Util.bytes(userInfo.getCredentialsSalt());
            String realName = getName();
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password, realName);
            return authenticationInfo;
        }
    }

    @Override
    public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        String username = (String) getAvailablePrincipal(principals);


        UserInfo userInfo = this.userInfoService.findByUsername(username);
        if (userInfo.getState() == UserState.DISABLE.getIndex()) {
            throw new LockedAccountException("账户已锁定，请联系技术人员");
        }
        for (SysRole role : userInfo.getRoleList()) {
            if (role.getAvailable() == false) {
                continue;
            }
            authorizationInfo.addRole(role.getRole());
            for (SysPermission p : role.getPermissions()) {
                if (p.getEnabled() == 1) {//禁用
                    continue;
                }
                if (!StringUtils.isEmpty(p.getPermission())) {
                    List<String> permissionList = Lists.newArrayList(p.getPermission().split(";"));
                    if (!CollectionUtils.isEmpty(permissionList)) {
                        authorizationInfo.addStringPermissions(permissionList);
                    }
                }
            }
        }
        return authorizationInfo;
    }

    /**
     * 清除所有缓存
     */
    public void clearCachedAuth() {
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();
        Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();//获取当前已登录的用户session列表
        if (!CollectionUtils.isEmpty(sessions)) {
            for (Session session : sessions) {
                Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
                if (obj instanceof SimplePrincipalCollection) {
                    SimplePrincipalCollection spc = (SimplePrincipalCollection) obj;
                    this.clearCachedAuthorizationInfo(spc);
                }
            }
        }
//        this.getAuthorizationCache().remove(SecurityUtils.getSubject().getPrincipals());
//        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());//刷新缓存权限，不能使用该方法
    }

    /**
     * 获取当前登录登录用户已经保存的权限信息
     * 可用于页面前端功能是否显示
     *
     * @return
     */
    public Collection<String> getStringPermissions() {
        return this.getAuthorizationInfo(SecurityUtils.getSubject().getPrincipals()).getStringPermissions();
    }
}